#!/usr/bin/python3
#******************************************************************************
# Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
# licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# ******************************************************************************/
"""
This is openEuler source counter script
"""

import sys
import os
import argparse
import re
import codecs

import sourcecounter

def _format_review_body(body):
    return re.sub("\"", "", body)

def _format_review_data(review_dict, separator):
    data = "{}:{}{}".format(review_dict.get("name"),
            _format_review_body(review_dict.get("body")),
            separator)
    return data

def _get_new_filename(oldname, num):
    if num == 0:
        return oldname
    (path, filename) = os.path.split(oldname)
    namelist = filename.split(".")
    basename = namelist[0]
    basename += "_" + str(num)
    if path:
        newname = path + "/" + basename
    else:
        newname = basename
    if len(namelist) > 1:
        for suffix in namelist[1:]:
            newname += "." + suffix
    return newname

def _format_merge_statistics(stat):
    data = "{},{},{},{},{},{},\"{}\",{},{},{},+{},-{},{},{}".format(stat["user"], stat["repo"], stat["branch"],
        stat["state"], stat["prNum"], stat["prType"], stat["prTitle"], stat["prAuthor"], stat["failCnt"], stat["rejectCnt"],
        stat["addition"], stat["deletion"], stat["total"], stat["reviewCnt"])
    reviewer_list = stat.get("reviewer")
    if reviewer_list:
        data += ",\""
        list_len = len(reviewer_list)
        if list_len == 1:
            review_dict = reviewer_list[0]
            data += _format_review_data(review_dict, "\"")
        elif list_len == 2:
            review_dict = reviewer_list[0]
            data += _format_review_data(review_dict, "\n")
            review_dict = reviewer_list[1]
            data += _format_review_data(review_dict, "\"")
        else:
            for review_dict in reviewer_list[0:-1]:
                data += _format_review_data(review_dict, "\n")
            review_dict = reviewer_list[-1]
            data += _format_review_data(review_dict, "\"")
        data += ",{}".format(stat["time"])
    return data

def source_merge_statistics(user_list, repo_list, owner, repo_type, branch, start_time, end_time, outfile):
    max_lines = 3000
    line_counter = 0
    file_num = 0
    fp = None
    header = "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}".format("user", "repo", "branch",
        "state", "prNo.", "prType", "prTitle", "prAuthor", "failCnt", "rejectCnt",
        "addition", "deletion", "total", "reviewCnt", "reviewer", "time")
    src_counter = sourcecounter.SourceCounter()
    all_repo_flag = False
    if not repo_list:
        all_repo_flag = True

    for user in user_list:
        if all_repo_flag:
            page = 1
            repo_list_tmp = src_counter.get_repos(owner, repo_type=repo_type, page=page)
        else:
            repo_list_tmp = repo_list
        while len(repo_list_tmp):
            for repo in repo_list_tmp:
                print("{user}:{repo}".format(user=user, repo=repo))
                stats = src_counter.merge_statistics(user, repo, owner, branch, start_time, end_time)
                if not stats:
                    continue
                for stat in stats:
                    data = _format_merge_statistics(stat)
                    if not fp:
                        fp = codecs.open(_get_new_filename(outfile, file_num), mode='w', encoding="utf_8_sig")
                        if not fp:
                            return False
                        print(header)
                        fp.write("{}\n".format(header))
                    print(data)
                    fp.write("{}\n".format(data))
                    fp.flush()
                    line_counter += 1
                    if line_counter % max_lines == 0:
                        file_num += 1
                        if fp:
                            fp.close()
                            fp = None
            if all_repo_flag:
                page += 1
                repo_list_tmp = src_counter.get_repos(owner, page=page)
            else:
                break
    if fp:
        fp.close()
    return True


def source_contribute_statistics(user_list, repo_list, owner, repo_type, branch, start_time, end_time, outfile):
    fp = codecs.open(outfile, mode='w', encoding="utf_8_sig")
    if not fp:
        return False
    header = "{},{},{},{},{},{},{},{},{}".format(
        "user", "commitCnt", "mergeCnt", "rejectCnt", "failCnt", "addition", "deletion", "total", "reviewCnt")
    print(header)
    fp.write("{}\n".format(header))

    src_counter = sourcecounter.SourceCounter()
    all_repo_flag = False
    if not repo_list:
        all_repo_flag = True

    for user in user_list:
        commitCnt = 0
        mergeCnt = 0
        rejectCnt = 0
        failCnt = 0
        addition = 0
        deletion = 0
        total = 0
        reviewCnt = 0
        if all_repo_flag:
            page = 1
            repo_list_tmp = src_counter.get_repos(owner, repo_type=repo_type, page=page)
        else:
            repo_list_tmp = repo_list

        while len(repo_list_tmp):
            for repo in repo_list_tmp:
                print("{user}:{repo}".format(user=user, repo=repo))
                stat = src_counter.contribute_statistics(user, repo, owner, branch, start_time, end_time)
                if not stat:
                    continue
                commitCnt += stat["commitCnt"]
                mergeCnt += stat["mergeCnt"]
                rejectCnt += stat["rejectCnt"]
                failCnt += stat["failCnt"]
                addition += stat["addition"]
                deletion += stat["deletion"]
                total += stat["total"]
                reviewCnt += stat["reviewCnt"]
                data = "{},{},{},{},{},+{},-{},{},{}".format(user, commitCnt, mergeCnt, rejectCnt,
                    failCnt, addition, deletion, total, reviewCnt)
                print(data)
            if all_repo_flag:
                page += 1
                repo_list_tmp = src_counter.get_repos(owner, page=page)
            else:
                break
        data = "{},{},{},{},{},+{},-{},{},{}".format(user, commitCnt, mergeCnt, rejectCnt,
            failCnt, addition, deletion, total, reviewCnt)
        print(data)
        fp.write("{}\n".format(data))
        fp.flush()

    fp.close()
    return True

def get_list(arg):
    lst = []
    if os.path.isfile(arg):
        with open(arg, 'r') as f:
            for ln in f:
                lst.extend(ln.strip().split(" "))
    else:
        lst = list(arg.strip().split(" "))
    return lst

def main():
    """
    Main entrance of the functionality
    """
    params = argparse.ArgumentParser()
    params.add_argument("-c", "--command", type=str,
                        choices=['merge', 'contribute'], required=True,
                        help="The subcommand, as follows: merge, contribute")
    params.add_argument("-u", "--user", type=str,
                        help="The username file or list")
    params.add_argument("-r", "--repo", type=str, default="",
                        help="The repository file or list, default is all repos")
    params.add_argument("-t", "--repotype", type=str, default="all",
                        help="The repository type, as follows: all/public/private, default is all")
    params.add_argument("-b", "--branch", type=str, default="all",
                        help="The branch name, default is all branch")
    params.add_argument("-p", "--project", type=str, default="src-openeuler",
                        help="The project name, default is src-openeuler")
    params.add_argument("-s", "--starttime", type=str, default="",
                        help="The start time, format is ISO 8601, default is not set")
    params.add_argument("-e", "--endtime", type=str, default="",
                        help="The end time, format is ISO 8601, default is not set")
    params.add_argument("-o", "--outfile", type=str, default="",
                        help="The output file, default is {command}_stat_result.csv")

    args = params.parse_args()

    if not args.command or not args.user:
        print("args invalid, please use -h for help")
        quit()

    user_list = get_list(args.user)
    if not user_list:
        print("user list invalid")
        quit()

    repo_list = []  # empty means all
    if args.repo != "":
        repo_list = get_list(args.repo)
        if not repo_list:
            print("repo list invalid")
            quit()

    if not args.outfile:
        outfile = "{}_stat_result.csv".format(args.command)
    else:
        outfile = args.outfile

    if args.command == "merge":
        source_merge_statistics(user_list, repo_list, args.project, args.repotype,
                args.branch, args.starttime, args.endtime, outfile)
    elif args.command == "contribute":
        source_contribute_statistics(user_list, repo_list, args.project, args.repotype,
                args.branch, args.starttime, args.endtime, outfile)


if __name__ == "__main__":
    main()
